package ar.com.utn.openqsb.lip.core;

import java.util.StringTokenizer;

import ar.com.utn.openqsb.lip.core.Constraint.Relation;
import ar.com.utn.openqsb.lip.core.Objective.Type;

public class Exercise
{
    private String name;

    private SimplexModel model;

    public Exercise(String name, int numVars, int numConstraints, boolean max)
    {
        this.name = name;
        // initialize an empty model
        this.model = new SimplexModel(numVars, numConstraints);
        Objective objective = new Objective(numVars);
        objective.setType(max ? Type.MAXIMIZE : Type.MINIMIZE);
        this.model.setObjective(objective);
    }

    public Exercise(String fileContent)
    {
        fromString(fileContent);
    }

    /**
     * @return the name
     */
    public String getName()
    {
        return name;
    }

    public int getNumVars()
    {
        return this.model.getNumVars();
    }

    public int getNumConstraints()
    {
        return this.model.getNumConstraints();
    }

    public SimplexModel getModel()
    {
        return model;
    }

    public void setObjectiveCoefficient(final int index, final double value)
    {
        this.model.getObjective().setCoefficient(index, value);
        System.out.println("Set " + index + " to " + value);
    }

    public void setObjectiveConstantTerm(final double value)
    {
        this.model.getObjective().setConstantTerm(value);
        System.out.println("Set constant term  " + value);
    }

    public void setConstraintCoefficient(final int index, final Constraint value)
    {
        this.model.setConstraint(index, value);
        System.out.println("Set constraint " + index);
    }

    @Override
    public String toString()
    {
        StringBuilder builder = new StringBuilder();
        builder.append(name).append("\n");
        builder.append(model.getNumVars()).append("\n");
        builder.append(model.getNumConstraints()).append("\n");
        for (double dv : model.getObjective().getCoefficients().toArray())
        {
            builder.append(dv).append("#");
        }
        builder.append(model.getObjective().getConstantTerm()).append("#");
        builder.append(model.getObjective().getType().equals(Type.MAXIMIZE) ? true : false).append("\n");
        for (Constraint c : model.getConstraints())
        {
            for (double dv : c.getCoefficients().toArray())
            {
                builder.append(dv).append("#");
            }

            builder.append(c.getRelation().name()).append("#");
            builder.append(c.getRightValue()).append("\n");
        }

        return builder.toString();
    }

    public void fromString(String fileContent)
    {
        StringTokenizer lineTokenizer = new StringTokenizer(fileContent, "\n");
        this.name = lineTokenizer.nextToken();
        int numVars = Integer.parseInt(lineTokenizer.nextToken());
        int numConstraints = Integer.parseInt(lineTokenizer.nextToken());
        // initialize an empty model
        this.model = new SimplexModel(numVars, numConstraints);

        // load objective
        StringTokenizer valueTokenizer = new StringTokenizer(lineTokenizer.nextToken(), "#");
        Objective objective = new Objective(numVars);
        for (int i = 0; i < numVars; i++)
        {
            objective.setCoefficient(i, Double.parseDouble(valueTokenizer.nextToken()));
        }
        objective.setConstantTerm(Double.parseDouble(valueTokenizer.nextToken()));
        boolean max = Boolean.parseBoolean(valueTokenizer.nextToken());
        objective.setType(max ? Type.MAXIMIZE : Type.MINIMIZE);
        this.model.setObjective(objective);

        // load constraints
        for (int j = 0; j < numConstraints; j++)
        {
            Constraint c = new Constraint(numVars);
            valueTokenizer = new StringTokenizer(lineTokenizer.nextToken(), "#");
            for (int i = 0; i < numVars; i++)
            {
                c.setCoefficient(i, Double.parseDouble(valueTokenizer.nextToken()));
            }
            c.setRelation(Relation.valueOf(valueTokenizer.nextToken()));
            c.setRightValue(Double.parseDouble(valueTokenizer.nextToken()));
            this.model.setConstraint(j, c);
        }
    }

}
